package actor

type Msg struct {
	SourceId string //来源哪个actor
	Data     []byte //数据内容
	SyncRsp  chan Msg
}

type IActor interface {
	Init()                              // 初始化
	Start()                             // 启动
	Stop()                              //关闭
	Send(msg Msg)                       //发送消息
	SyncSend(msg Msg, syncRsp chan Msg) //同步发送消息
	Catalog() string                    // 别名
	ActorId() string                    // actor编号
	SetCatalog(string)                  // 设置别名
	SetActorId(string)                  // 设置actor编号
	Handle(msg Msg)
	RegisterHandle(func(msg Msg))
}

// 默认actor
type DefaultActor struct {
	queue    *Queue        //mailbox 就是一个线程安全的并发队列，其实这里应该实现1个mpsc无锁队列最为合适。
	stop     chan struct{} //关闭actor通道
	newmsg   chan struct{} //新消息通道
	handle   func(msg Msg) //处理函数
	catalog  string        // 别名
	actoriId string        // actor编号
}

// actor初始化
func (q *DefaultActor) Init() {
	q.queue = &Queue{}
	q.stop = make(chan struct{})
	q.newmsg = make(chan struct{})
}

// actor别名
func (q *DefaultActor) Catalog() string {
	return q.catalog
}

// actor编号
func (q *DefaultActor) ActorId() string {
	return q.actoriId
}

// 设置别名
func (q *DefaultActor) SetCatalog(catalog string) {
	q.catalog = catalog
}

// 设置actor编号
func (q *DefaultActor) SetActorId(actorId string) {
	q.actoriId = actorId
}

// 启动actor
func (q *DefaultActor) Start() {
	go func() {
		loop := func() {
			for {
				msg, exist := q.queue.Pop()
				if !exist {
					break
				}
				q.handle(msg)
			}
		}
		// 循环处理消息
		for {
			select {
			case <-q.stop: //关停actor
				return
			case <-q.newmsg: //新消息
				loop()
			}
		}

	}()
}

// 关停actor
func (q *DefaultActor) Stop() {
	q.stop <- struct{}{}
}

func (q *DefaultActor) RegisterHandle(handle func(msg Msg)) {
	q.handle = handle
}

// 发送消息
func (q *DefaultActor) Send(msg Msg) {
	//这里一般来说还是要限制一下消息队列的长度的
	// 将消息放入队列
	q.queue.Push(msg)
	q.newmsg <- struct{}{}
}

func (q *DefaultActor) SyncSend(msg Msg, syncRsp chan Msg) {
	//这里一般来说还是要限制一下消息队列的长度的
	// 将消息放入队列
	if syncRsp != nil {
		msg.SyncRsp = syncRsp
	}
	q.queue.Push(msg)
	q.newmsg <- struct{}{}
}
